package com.frank.loadinglibrary.common.element;

import com.frank.loadinglibrary.base.baseanimations.BaseAnimationController;
import com.frank.loadinglibrary.base.baseelement.BaseElement;
import com.frank.loadinglibrary.base.baseelement.IComponentCallback;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.agp.utils.TextTool;

import java.util.ArrayList;

/**
 * @author SUQI
 * @date 2021/6/4
 * @description
 **/
public class StripLoadingElement extends BaseElement implements BaseAnimationController.IAnimationController<AnimatorValue> {
    private Paint mPaint = new Paint();

    private Paint shadowPaint = new Paint();

    private float stripPercent = 0.3f;

    private float radius;

    private ArrayList<Point> pointArrayList = new ArrayList<>();

    private boolean isInitialized = false;

    private String backgroundColor;

    private String stripeColor;

    private String shadowColor;

    private int frame = 40;

    private int pixelPerFrame = 3;

    private StripLoadingElement(IComponentCallback iComponentCallback) {
        this.callback = iComponentCallback;
    }

    @Override
    public ArrayList<AnimatorValue> onCreateAnimators() {
        ArrayList<AnimatorValue> list = new ArrayList<>();
        AnimatorValue animatorValue = new AnimatorValue();
        animatorValue.setDuration(1000 / frame);
        animatorValue.setLoopedCount(Animator.INFINITE);
        animatorValue.setLoopedListener(animator -> callback.reflushComponent());
        list.add(animatorValue);
        return list;
    }

    @Override
    public void onAnimationReset() {
        //do nothing because donot need to reset animation params
    }

    @Override
    public BaseAnimationController.IAnimationController initAnimationController() {
        return this;
    }

    @Override
    public void initPaint() {
        super.initPaint();
        mPaint.setColor(new Color(Color.getIntColor(backgroundColor)));
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setAntiAlias(true);

        shadowPaint.setColor(new Color(Color.getIntColor(shadowColor)));
        MaskFilter maskFilter = new MaskFilter(15
                , MaskFilter.Blur.OUTER);
        shadowPaint.setMaskFilter(maskFilter);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        int width = (int) getWidth();
        int height = (int) getHeight();


        float loadingTop = (1 - stripPercent) * height / 2f;
        float loadingBottom = (1 + stripPercent) * height / 2f;

        RectFloat outerRect = new RectFloat(0, loadingTop, width, loadingBottom);
        canvas.drawRoundRect(outerRect, radius, radius, shadowPaint);

        RectFloat rectFloat = new RectFloat(0, loadingTop, width, loadingBottom);
        canvas.drawRoundRect(rectFloat, radius, radius, mPaint);

        int stripeWidth = width / 10;
        int intervalWidth = width / 10;

        int count = width / (stripeWidth + intervalWidth) + 2;

        if (!isInitialized) {
            for (int i = 0; i < count; i++) {
                Point point = new Point();
                point.position[0] = (float) ((-1 + i) * (stripeWidth + intervalWidth));
                pointArrayList.add(point);
            }
            isInitialized = true;
        } else {
            if (pointArrayList.get(pointArrayList.size() - 1).getPointX() > width) {
                pointArrayList.get(pointArrayList.size() - 1).position[0] = (float) (-stripeWidth - intervalWidth);
                pointArrayList.add(0, pointArrayList.get(pointArrayList.size() - 1));
                pointArrayList.remove(pointArrayList.size() - 1);
            }
            for (int i = 0; i < count; i++) {
                pointArrayList.get(i).position[0] = pointArrayList.get(i).position[0] + pixelPerFrame;
            }
        }

        for (int i = 0; i < count; i++) {
            Path path = new Path();
            canvas.save();
            path.reset();
            float topStartX = pointArrayList.get(i).getPointX();
            float bottomStartX = topStartX + intervalWidth;

            path.moveTo(pointArrayList.get(i).getPointX(), rectFloat.top);
            Point leftCenterPoint = new Point((topStartX + bottomStartX) / 2, (rectFloat.top + rectFloat.bottom) / 2);
            path.quadTo(new Point((bottomStartX + 3 * topStartX) / 4f + 7, (rectFloat.bottom + 3 * rectFloat.top) / 4f), leftCenterPoint);
            path.quadTo(new Point((3 * bottomStartX + topStartX) / 4f - 7, (3 * rectFloat.bottom + rectFloat.top) / 4f), new Point(bottomStartX, rectFloat.bottom));
            path.lineTo(bottomStartX + stripeWidth, rectFloat.bottom);
            Point rightCenterPoint = new Point((topStartX + bottomStartX + 2 * stripeWidth) / 2, (rectFloat.top + rectFloat.bottom) / 2);
            path.quadTo(new Point((3 * (bottomStartX + stripeWidth) + topStartX + stripeWidth) / 4f - 7, (3 * rectFloat.bottom + rectFloat.top) / 4f), rightCenterPoint);
            path.quadTo(new Point((bottomStartX + stripeWidth + 3 * (topStartX + stripeWidth)) / 4f + 7, (rectFloat.bottom + 3 * rectFloat.top) / 4f), new Point(topStartX + stripeWidth, rectFloat.top));
            canvas.clipPath(path, Canvas.ClipOp.INTERSECT);
            canvas.drawColor(Color.getIntColor(stripeColor), BlendMode.SRC);
            canvas.restore();
        }
    }



    public static class StripLoadingBuilder {
        private IComponentCallback iComponentCallback;
        private String backgroundColor;
        private String stripeColor;
        private String shadowColor;
        private float radius = 20f;

        public StripLoadingBuilder(IComponentCallback iComponentCallback) {
            this.iComponentCallback = iComponentCallback;
        }

        public StripLoadingBuilder setBackgroundColor(String backgroundColor) {
            this.backgroundColor = backgroundColor;
            return this;
        }

        public StripLoadingBuilder setStripeColor(String stripeColor) {
            this.stripeColor = stripeColor;
            return this;
        }

        public StripLoadingBuilder setShadowColor(String shadowColor) {
            this.shadowColor = shadowColor;
            return this;
        }

        public StripLoadingBuilder setRadius(float radius) {
            this.radius = radius;
            return this;
        }

        private void apply(StripLoadingElement e) {
            e.backgroundColor = TextTool.isNullOrEmpty(this.backgroundColor) ? "#ffffff" : this.backgroundColor;
            e.stripeColor = TextTool.isNullOrEmpty(this.backgroundColor) ? "#338FE8" : this.stripeColor;
            e.shadowColor = TextTool.isNullOrEmpty(this.backgroundColor) ? "#ffffff" : this.shadowColor;
            e.radius = this.radius > 0 ? this.radius : 20;
            e.initPaint();
        }

        public StripLoadingElement build() {
            StripLoadingElement stripLoadingElement = new StripLoadingElement(iComponentCallback);
            apply(stripLoadingElement);
            return stripLoadingElement;
        }
    }
}
